package cn.edu.zime.tjh.server;

import cn.edu.zime.tjh.handler.EchoServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.util.function.BiConsumer;

public class EchoServer {
    private static EchoServer s_instance = null;

    private final static int PORT = 9000;
    
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel serverChannel;


    private EchoServer(){

    }

    public static EchoServer getInstance(){
        if (s_instance == null){
            s_instance = new EchoServer();
        }

        return s_instance;
    }

    public void start(){
        start(PORT);
    }
    
    public void start(int port){
        // 创建主从Reactor线程组
        bossGroup = new NioEventLoopGroup(1);  // 接收连接
        workerGroup = new NioEventLoopGroup(); // 处理业务

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)  // 使用NIO传输
                    .option(ChannelOption.SO_BACKLOG, 128)  // 连接队列大小
                    .childOption(ChannelOption.SO_KEEPALIVE, true)  // 保持长连接
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline p = ch.pipeline();
                            // 添加字符串编解码器
                            p.addLast(new StringDecoder());
                            p.addLast(new StringEncoder());
                            // 添加自定义处理器
                            p.addLast(new EchoServerHandler());
                        }
                    });

            // 绑定端口并启动服务器
            ChannelFuture f = b.bind(port).sync();
            serverChannel = f.channel();
            System.out.println("Echo server started, listening on port: " + port);

            // 等待服务器通道关闭
            serverChannel.closeFuture().sync();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
        finally {
            // 优雅关闭线程组
            stop();
        }
    }
    
    public void stop() {
        if (serverChannel != null && serverChannel.isActive()) {
            serverChannel.close();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        System.out.println("Echo server stopped");
    }
    
    public boolean isRunning() {
        return serverChannel != null && serverChannel.isActive();
    }
    
    public void setLogCallback(BiConsumer<String, String> logCallback) {
        EchoServerHandler.setLogCallback(logCallback);
    }
    
    public void broadcastMessage(String message) {
        EchoServerHandler.broadcastMessage(message);
    }
    
    public void sendToClient(String clientId, String message) {
        EchoServerHandler.sendMessageToClient(clientId, message);
    }
}
